/**
 * @file memAndSem.c
 * @author Mario Alvarez (mario.alvarezp@estudiante.uam.es) J. Angel Gonzalez (joseangel.gonzalezp@estudiante.uam.es)
 * @date 26-03-2011
 *
 * Biblioteca de gestion de acceso a recursos compartidos mediante semaforos. Incluye funciones de control de acceso
 * a zona critica.
*/

#include "memAndSem.h"

int getMutex(int key)
{
	int semId;
	
	semId = semget(key, 1, IPC_EXCL|IPC_CREAT|SHM_R|SHM_W);			/*Reserva de semaforos en exclusiva*/
	if(semId==-1){
	  	semId= semget(key, 1, IPC_CREAT|SHM_R|SHM_W);				/*Reserva de semaforo sin exclusividad*/
	  	
	  	return semId;
  	}
  	
  	if(semctl(semId, 0, SETVAL, 1)==-1){								/*Inicializacion del semaforo*/
  		return -1;
  	}
  	
  	return semId;
}


int freeMutex(int id)
{
	return 0;
}

int down(int id, int numsem)
{
	struct sembuf op;
	int ret=-1;
	
	op.sem_num=numsem;						/*Posicion del semaforo en el array*/
	op.sem_op=-1;							/*Decrementar*/
	op.sem_flg=0;							/*Sin flags*/
	
	do{
		ret=semop(id, &op, 1);
	}while(ret==-1 && errno==EINTR);		/*Reiterar la espera en caso de interrupcion por sennal (errno==EINTR)*/
	
	
	return ret;
}

int up(int id, int numsem)
{
	struct sembuf op;
	int ret=-1;
	
	op.sem_num=numsem;						/*Posicion del semaforo en el array*/
	op.sem_op=1;							/*Incrementar*/
	op.sem_flg=0;							/*Sin flags*/
	
	ret=semop(id, &op, 1);
	
	return ret;
}

int downDireccionable(int id, int numsem, short *bifurcar, void (*alternativeFunction) (void))
{
	struct sembuf op;
	int ret=-1;

	op.sem_num=numsem;						/*Posicion del semaforo en el array*/
	op.sem_op=-1;							/*Decrementar*/
	op.sem_flg=0;							/*Sin flags*/
	
	do{
		ret=semop(id, &op, 1);
	}while(ret==-1 && !(*bifurcar) && errno!=EIDRM);		/*Reiterar mientras la espera sea interrumpida de forma anomala y el flag de bifurcacion se encuentre a 0*/
	
	if(*bifurcar){							/*Flag de bifurcacion activo*/
		alternativeFunction();				/*Llamada a funcion alternativa*/
		ret=1;								/*Salida correcta (Actuo segun lo previsto)*/
	}

	return ret;
}
